/*================ server.c ======================*/ 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "server.h"
#include "comunication.h"

int strcasecmp(const char *s1, const char *s2);
char *strdup(const char *s1);

typedef void (*ActionType)();

/*	Estados	*/
#define WP 0				/*	Waiting packet			*/
#define WRR 1				/*	Waiting packet response	*/
/*	Eventos	*/
#define PACKET 0			/*	Packet Received			*/
#define RR 1				/*	Response received		*/
#define TIMER 2				/*	Timer Event				*/
/*	BASE DE DADOS	*/
char *put_list[128];
int put_count = 0;
int hasId;

char *ID;
int STATE; /* 0 = RED; 1 = YELLOW; 2 = GREEN */
int LABEL;
char* SON;
char *rcv_pdu;
char *send_pdu;
char *message;

int machine_state;
int machine_event;
int pdu_op;


int processPdu(char *pdu){
	int i, op;
	op = pdu[1];
	for(i = 0; i < 128 && pdu[i+2] != '\0'; i++){
		message[i] = pdu[i+2];
	}
	message[i] = '\0';
	return op;
}
/*	À espera de um pacote para enviar pela rede	*/
/*	Deve enviar pela rede o pacote 				*/
void PacketOverWP() {
	bks_send_server_udp(send_pdu);
	machine_state = WRR;
	machine_event = RR;
}

/*	Á espera que chegue um pacote da rede	*/
/*	Deve receber esse pacote				*/
void RROverWRR() {
	int op;
	bks_rcv_udp(rcv_pdu);
	memset(message, 0, 128);
	op = processPdu(rcv_pdu);
	memset(rcv_pdu, 0, 128);
	printf("DEBUG de message: %s\n", message);
	switch(op){
		case 1:
			receive_put(message);
			break;
		case 11:
			if(!hasId){
				strcpy(ID, message);
				hasId = 1;
			}
			receive_synch();
			printf("CASE 11\nSERVER ID: %s, STATE: %d, SON: %s\n", ID, STATE, SON);
			break;
		case 12:
			STATE = 2;
			printf("CASE 12\nSERVER ID: %s, STATE: %d, SON: %s\n", ID, STATE, SON);
			break;
		case 13:
			SON = strdup(message);
			printf("CASE 13\nSERVER ID: %s, STATE: %d, SON: %s\n", ID, STATE, SON);
			break;
		default:
			break;
	}
}

void PacketOverWRR() {
	printf("User Error");
/*	AlertOnUserError;*/
}

void RROverWP() {
	printf("trnasmission Error");
/*	if(N < > S)
	AlertOnTransmissionError;*/
}
void TimerOverWP() {
/*	AlertOnOperatingSystemError;*/
}

void TimerOverWRR() {
/*	SendIFrame(1 - S);
	FireTimer;*/
}

ActionType ActionsTable[3][2] = {	{PacketOverWP	, PacketOverWRR	},
									{RROverWP		, RROverWRR		},
									{TimerOverWP	, TimerOverWRR	}};

/* initiate the Users DB */
void read_users(){
	char* users = readFile(USERS_FILE);
	char *user, *name, *pass, *locale;
	char*  user_aux_list[USERS_LIST_SIZE];
	int i = 0;
	user = strtok(users, "\n");
	while(user != NULL){
		user_aux_list[i++] = user;
		user = strtok(NULL, "\n");
	}
	user_aux_list[i] = NULL;
	i = 0;
	while(user_aux_list[i] != NULL && USERS_LIST_SIZE > i){
		name = strtok(user_aux_list[i], " \n\t");
		pass = strtok(NULL, " \n\t");
		locale = strtok(NULL, " \n\t");
		if(name == NULL || pass == NULL || locale == NULL)
			break;
		USERS_LIST[i] = create_user(name, pass, locale);
		++i;
	}

}

void read_coords(){
	char *coords = readFile(COORDS_FILE);
	char *coord, *server, *aux;
	char* servers[SERVERS_COORD_LIST_SIZE];
	char* coords_aux_list[SERVERS_COORD_LIST_SIZE];
	int i = 0;
	coord = strtok(coords, "\n");
	while(coord != NULL){
		coords_aux_list[i++] = coord;
		coord = strtok(NULL, "\n");
	}
	coords_aux_list[i] = NULL;
	i = 0;
	while(coords_aux_list[i] != NULL && SERVERS_COORD_LIST_SIZE > i){
		server = strtok(coords_aux_list[i], " \n\t");
		int j = 0;
		while(j < SERVERS_COORD_LIST_SIZE && (aux = strtok(NULL, "\t")) != NULL){
			servers[j] = aux;
			j++;
		}
		if(server == NULL)
			break;
		SERVERS_COORD[i] = create_server_coord(server, servers, j);
		++i;
	}
	SERVERS_COORD[i] = NULL;
}

/* initiate the countries DB */
void read_countries(){
	char *countries = readFile(COUTRIES_FILE);
	char *locale, *name, *server, *country;
	char* country_aux_list[COUNTRIES_LIST_SIZE];
	int i = 0;
	country = strtok(countries, "\n");
	while(country != NULL){
		country_aux_list[i++] = country;
		country = strtok(NULL, "\n");
	}
	country_aux_list[i] = NULL;
	i = 0;
	while(country_aux_list[i] != NULL && COUNTRIES_LIST_SIZE > i){
		locale = strtok(country_aux_list[i], " \n\t");
		name = strtok(NULL, " \n\t");
		server = strtok(NULL, " \n\t");
		if(locale == NULL || name == NULL || server == NULL)
			break;
		COUNTRIES_LIST[i] = create_country(locale, name, server);
		++i;
	}
}

void insert_data(char *locale, char *number, char *date, int putsize){
	char *put = (char*) malloc(sizeof(char) * putsize);
	memset(put, '\0', putsize);
	strcat(put, locale);
	strcat(put, " ");
	strcat(put, number);
	strcat(put, " ");
	strcat(put, date);
	put_list[put_count] = put;
	put_count++;
}

/* receive a put PDU */
void receive_put(char *pdu){
	char *user, *pass, *locale, *number, *date;
	int putsize = 3;
	locale = strtok(pdu, " "); putsize += strlen(locale);
	number = strtok(NULL, " "); putsize += strlen(number);
	date = strtok(NULL, " "); putsize += strlen(date);
	user = strtok(NULL, " ");
	pass = strtok(NULL, "\0");
	if(check_user(USERS_LIST, 100, user, pass, locale) != 1){
		return;
	}
	memset(send_pdu, '\0', 128);
	if(STATE != 2){
		send_pdu[0] = strlen(SON) + 3;
		send_pdu[1] = 3;
		send_pdu = strcat(send_pdu, SON);
	}else {
		insert_data(locale, number, date, putsize);
		send_pdu[0] = 2;
		send_pdu[1] = 2;
	}
	machine_state = WP;
	machine_event = PACKET;
}

/* receive a get PDU */
int receive_get(char* user, char* pass){
	printf("chegou Get - %s - %s\n", user, pass);
	return 0;
}


/* receive a synch PDU */
void receive_synch(){
	char label_str[8];
	char state_str[8];
	memset(send_pdu, 0, 128);
	sprintf(label_str, "%d", LABEL);
	sprintf(state_str, "%d", STATE);
	send_pdu[0] = 6 + strlen(SON) + strlen(label_str) + strlen(state_str) + strlen(ID);
	send_pdu[1] = 14;
	strcat(send_pdu, label_str);
	strcat(send_pdu, " ");
	strcat(send_pdu, state_str);
	strcat(send_pdu, " ");
	strcat(send_pdu, SON);
	strcat(send_pdu, " ");
	strcat(send_pdu, ID);
	machine_state = WP;
	machine_event = PACKET;
}

/* main function */
int main(int argc, char *argv[]){
	int port;
	rcv_pdu = (char *)malloc(128*sizeof(char));
	send_pdu = (char *)malloc(128*sizeof(char));
	message = (char*)malloc(128*sizeof(char));
	ID = (char*)malloc(128*sizeof(char));
	memset(ID, 0, 128);
	hasId = 0;
	STATE = 0;
	LABEL = 0;
	SON = "S0";
	read_users();
	read_countries();
	read_coords();
	if(argc != 2){
		printf("ERRO\n");
		exit(0);
	}
	port = atoi(argv[1]);
	printf("id: %s\n", ID);
	bks_init_server_socket(port);
	machine_state = WRR;
	machine_event = RR;
	while(1){
		ActionsTable[machine_event][machine_state]();
	}
	bks_close();
	return 0;
}
